package com.sl.sdn.repository.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.sl.sdn.dto.OrganDTO;
import com.sl.sdn.entity.enums.OrganTypeEnum;
import com.sl.sdn.repository.OrganRepository;
import com.sl.transport.common.util.BeanUtil;
import org.neo4j.driver.types.Node;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;


@Component
public class OrganRepositoryImpl implements OrganRepository {

    @Resource
    private Neo4jClient neo4jClient;


    @Override
    public OrganDTO findByBid(Long bid) {
        // 定义cql: MATCH (n) WHERE n.bid = 替换好变量 RETURN n
        // 执行查询得到结果: CollUtil.getFirst(executeQuery(cql))
        String cql = StrUtil.format("MATCH (n) WHERE n.bid = {} RETURN n", bid);
        return CollUtil.getFirst(executeQuery(cql));
    }

    @Override
    public List<OrganDTO> findAll(String name) {
        // 去除特殊引号字符  '  "    提示: cql中会进行拼接操作，如果有引号影响语义
        // 定义cql:
        // 如果查询name为空则 查询全部    cql: MATCH (n) RETURN n
        // 如果不为空 查询节点名字包含的信息  cql:  MATCH (n) WHERE n.name CONTAINS '变成name变量信息' RETURN n
        // 执行并解析结果: executeQuery(cql)

        String cql = "";
        if (StrUtil.isEmpty(name)) {
            cql = "MATCH (n) RETURN n";

        } else {
            cql = StrUtil.format("MATCH (n) WHERE n.name CONTAINS '{}' RETURN n", name);
        }
        return executeQuery(cql);
    }

    /**
     * 抽取通用的结果解析方法
     *
     * @param cypherQuery 解析方法中未绑定参数，需要传入前自行拼接好
     * @return
     */
    private List<OrganDTO> executeQuery(String cypherQuery) {
        //执行查询->设置返回类型->处理结果映射->.all()返回集合
        //处理结果映射:
        //  1. record中获取 n 节点信息获取map参数      提示: cql中return  n
        //  2. 将map转为OrganDTO     tips: BeanUtil
        //  3. 设置经纬度          tips: map中获取location 强转为InternalPoint2D类型
        //  4. 设置节点类型         tips: 取Node中第一个标签  通过OrganTypeEnum获取code值
        //  5. 返回organDto机构对象
        // 返回集合
        // 根据上面的提示完成代码

        Collection<OrganDTO> all = neo4jClient.query(cypherQuery)
                // 封装为这个对象
                .fetchAs(OrganDTO.class)
                .mappedBy((typeSystem, record) -> {


                    OrganDTO organDTO = new OrganDTO();

                    // 这个只能变成node 你可以通过debug来看到究竟是什么类型
                    Node node = record.get(0).asNode();

                    Map<String, Object> map = node.asMap();
                    // 如果有些没有匹配上可能会报错,因此要忽略这个错误
                    organDTO = BeanUtil.toBeanIgnoreError(map, OrganDTO.class);

                    // 我们自己设置下面的三种属性
                    organDTO.setType(OrganTypeEnum.valueOf(CollUtil.getFirst(node.labels())).getCode());
                    organDTO.setLatitude(BeanUtil.getProperty(map.get("location"), "x"));
                    organDTO.setLongitude(BeanUtil.getProperty(map.get("location"), "y"));

                    return organDTO;
                }).all();

        return (List<OrganDTO>) all;
    }
}
